package collector

import (
	"crypto/tls"
	"errors"
	"fmt"
	"net/url"
	"strings"

	"github.com/Telmate/proxmox-api-go/proxmox"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
)

var b2f = map[bool]float64{true: 1, false: 0}
var path = "/api2/json"

func setUrl(target string) string {
	if !strings.Contains(target, "://") {
		target = "https://" + target
	}

	u, err := url.Parse(target)
	if err != nil {
		fmt.Println("Parse error:", err)
	}

	u.Scheme = "https"
	if !strings.Contains(u.Host, ":") {
		u.Host = u.Host + ":8006"
	}
	u.Path = path
	return u.String()
}

func (c *Collector) Login() (*proxmox.Client, error) {
	tlsconf := &tls.Config{InsecureSkipVerify: true}

	if c.pveAddr == "" || (UserInfo{} == c.options.UserInfo) {
		log.Errorln("url or userinfo error")
		return nil, errors.New("url or userinfo error")
	}

	client, err := proxmox.NewClient(setUrl(c.pveAddr), nil, tlsconf, "", 300)
	if err != nil {
		log.Errorln("create pve client error:", err)
		return nil, err
	}

	err = client.Login(c.options.UserInfo.Username, c.options.UserInfo.Password, "otpcode")
	if err != nil {
		log.Errorln("login error:", err)
		return nil, err
	}

	return client, nil
}

func (c *Collector) ScrapePveHost(ch chan<- prometheus.Metric) {
	client, err := c.Login()
	if err != nil {
		return
	}

	err = c.ClusterStatus(ch, client)
	if err != nil {
		log.Errorln("collect cluster status error", err)
	}

	err = c.ClusterResources(ch, client)
	if err != nil {
		log.Errorln("collect cluster status error", err)
	}
}

func (c *Collector) ClusterStatus(ch chan<- prometheus.Metric, client *proxmox.Client) error {
	datas, err := client.GetClusterStatus()
	if err != nil {
		return err
	}

	for _, data := range datas["data"].([]interface{}) {
		d := data.(map[string]interface{})
		if d["type"] == "node" {
			label_id := d["id"].(string)
			label_name := d["name"].(string)
			value := d["online"].(float64)
			c.registerConstMetricGauge(ch, "nodeinfo", value, label_id, label_name)
		}

		if d["type"] == "cluster" {
			label_name := d["name"].(string)
			nodes := d["nodes"].(float64)
			value := d["quorate"].(float64)
			c.registerConstMetricGauge(ch, "clusterinfo", value, label_name)
			c.registerConstMetricGauge(ch, "clusternodes", nodes, label_name)
		}
	}

	return nil
}

func (c *Collector) ClusterResources(ch chan<- prometheus.Metric, client *proxmox.Client) error {
	resource, err := client.GetResources()
	if err != nil {
		return err
	}

	for _, data := range resource["data"].([]interface{}) {
		d := data.(map[string]interface{})

		switch d["type"] {
		case "qemu":
			label_id := d["id"].(string)
			label_name := d["name"].(string)
			value := d["status"] == "running"
			c.registerConstMetricGauge(ch, "vmup", b2f[value], label_id, label_name)
		case "storage":
			label_id := d["id"].(string)
			label_node := d["node"].(string)
			local_storage := d["storage"].(string)
			value := d["status"] == "available"
			c.registerConstMetricGauge(ch, "storageinfo", b2f[value], label_id, label_node, local_storage)
		}

		for k, v := range d {
			if _, ok := resourceDescs[k]; ok {
				label_id := d["id"].(string)
				c.registerConstMetricGauge(ch, k, v.(float64), label_id)
			}
		}
	}

	return nil
}
